import { transformStringAsTemplate } from "./base";
import {
  hasImportDefaultSpecifier,
  isIdentifier,
  isNamespaceDeclaration,
} from "./esyntax";
import {
  ArrayLiteralDesc,
  ObjectLiteralDesc,
  BaseImportDeclaration,
  ImportSpecifier,
  ExpString,
  ParsedFormItem,
} from "@/types";

export function generateImportDeclarationCode(
  declaration: BaseImportDeclaration
) {
  const { source, specifiers } = declaration;

  if (isNamespaceDeclaration(declaration)) {
    return `import * as ${specifiers[0].local} from "${source}"`;
  }

  const importSpecifiers = specifiers.filter(
    (spec) => spec.type === "ImportSpecifier"
  ) as ImportSpecifier[];
  let attachments = importSpecifiers
    .map((spec) => {
      const { imported, local } = spec;
      return imported !== local ? `${imported} as ${local}` : imported;
    })
    .join(", ");
  attachments = attachments ? `{ ${attachments} }` : "";

  if (hasImportDefaultSpecifier(declaration)) {
    const _deafult = declaration.specifiers[0].local;
    return attachments
      ? `import ${_deafult}, ${attachments} from "${source}"`
      : `import ${_deafult} from "${source}"`;
  }
  return attachments
    ? `import ${attachments} from "${source}"`
    : `import { } from "${source}"`;
}

export function generateObjectLiteral(
  input: string[] | [string, string?][] | ObjectLiteralDesc
): string {
  if (Array.isArray(input)) {
    if (!input.length) return "{}";
    if (typeof input[0] === "string") {
      // { p1, p2, p3 }
      return `{ ${input.join(", ")} }`;
    } else {
      // { p1, p2: p3 }
      return `{ ${input.map(([a, b]) => (b ? `${a}: ${b}` : a)).join(", ")} }`;
    }
  } else {
    const keys = Object.keys(input);
    if (!keys.length) return "{}";
    const ret = "{ ${placeholder} }";
    const items = keys.map<string>((key) => {
      const value = input[key];
      const valueStr = Array.isArray(value)
        ? generateArrayLiteral(value)
        : typeof value === "object"
        ? generateObjectLiteral(value)
        : value;
      const safekey = isIdentifier(key) ? key : `"${key}"`;
      return `${safekey}: ${valueStr}`;
    });
    return transformStringAsTemplate(ret, {
      placeholder: items.join(", "),
    });
  }
}

export function generateArrayLiteral(desc: ArrayLiteralDesc): string {
  if (!desc.length) return "[]";
  const ret = "[ ${placeholder} ]";
  const items = desc.map<string>((value) =>
    Array.isArray(value)
      ? generateArrayLiteral(value)
      : typeof value === "object"
      ? generateObjectLiteral(value)
      : value
  );
  return transformStringAsTemplate(ret, {
    placeholder: items.join(", "),
  });
}

/** exp to exp-string */
export function stringifyExp(val: unknown): ExpString {
  if (typeof val === "string") {
    return `"${val}"`;
  } else if (val && typeof val === "object") {
    return JSON.stringify(val);
  } else {
    return String(val);
  }
}

export function generateFormObjectLiteral(items: ParsedFormItem[]) {
  return generateObjectLiteral(
    items.reduce((formObj, item) => {
      const { field, component } = item;
      const initialValue = stringifyExp(component.initialValue || "");
      formObj[field] = initialValue;
      return formObj;
    }, {} as Data)
  );
}
